import datetime
import os.path

import numpy as np
import pandas as pd

from pandas import DateOffset
from pandas import DatetimeIndex
from pandas import PeriodIndex
from pandas.tseries.offsets import MonthEnd
from pandas.tseries.offsets import MonthEnd as ME
from pandas.tseries.offsets import MonthBegin as MB
from pandas.tseries.offsets import QuarterEnd as QE
from pandas.tseries.offsets import YearBegin as YB
from pandas.tseries.offsets import YearEnd as YE

transformer_data_string_map = {
    # 日变日 当期值
    '日_当期值_日_当期同比': ['当日同比', 'A', 500],
    '日_当期值_日_同比环差': ['当日同比_当日环差', 'A_A', 500],
    '日_当期值_日_当期环比': ['当日环比', 'A', 5],
    '日_当期值_日_累计值': ['-'],
    '日_当期值_日_累计同比': ['-'],
    '日_当期值_日_当期值': ['-'],
    # 日变日 期末值
    '日_期末值_日_期末值': ['-'],
    '日_期末值_日_期末同比': ['当日同比', 'A', 500],
    '日_期末值_日_同比环差': ['当日同比_当日环差', 'A_A', 500],
    '日_期末值_日_环比': ['当日环比', 'A', 5],
    # 日变周
    '日_当期值_周_当期同比': ['-'],
    '日_当期值_周_当期环比': ['当周均值_当周环比', 'B_A', 30],
    '日_当期值_周_累计值': ['-'],
    '日_当期值_周_累计同比': ['-'],
    '日_当期值_周_当期值': ['当周总值', 'B', 30],
    # 日变周 期末值
    '日_期末值_周_期末同比': ['-'],
    '日_期末值_周_当期环比': ['当周后值_当周环比', 'B_A', 30],
    '日_期末值_周_累计值': ['-'],
    '日_期末值_周_累计同比': ['-'],
    '日_期末值_周_期末值': ['当周后值', 'B', 30],
    # 日变旬
    '日_当期值_旬_当期同比': ['当旬均值_当旬同比', 'B_A', 500],
    '日_当期值_旬_同比环差': ['当旬均值_当旬同比_当旬环差', 'B_A_A', 500],
    '日_当期值_旬_当期环比': ['当旬均值_当旬环比', 'B_A', 60],
    '日_当期值_旬_累计值': ['-'],
    '日_当期值_旬_累计同比': ['-'],
    '日_当期值_旬_当期值': ['当旬总值', 'B', 30],
    # 日变旬 期末值
    '日_期末值_旬_期末同比': ['当旬后值_当旬同比', 'B_A', 500],
    '日_期末值_旬_同比环差': ['当旬后值_当旬同比_当旬环差', 'B_A_A', 500],
    '日_期末值_旬_当期环比': ['当旬后值_当周环比', 'B_A', 30],
    '日_期末值_旬_累计值': ['-'],
    '日_期末值_旬_累计同比': ['-'],
    '日_期末值_旬_期末值': ['当旬后值', 'B', 30],
    # 日变月
    '日_当期值_月_当期同比': ['当月均值_当月同比', 'B_A', 500],
    '日_当期值_月_同比环差': ['当月均值_当月同比_当月环差', 'B_A_A', 500],
    '日_当期值_月_当期环比': ['当月均值_当月环比', 'B_A', 90],
    '日_当期值_月_累计值': ['当月总值_累计值', 'B_A', 300],
    '日_当期值_月_累计同比': ['当月总值_累计值_当月同比', 'B_A_A', 500],
    '日_当期值_月_当期值': ['当月总值', 'B', 60],
    # 日变月 期末值
    '日_期末值_月_期末同比': ['当月后值_当月同比', 'B_A', 500],
    '日_期末值_月_同比环差': ['当月后值_当月同比_当月环差', 'B_A_A', 500],
    '日_期末值_月_当期环比': ['当月后值_当月环比', 'B_A', 90],
    '日_期末值_月_累计值': ['-'],
    '日_期末值_月_累计同比': ['-'],
    '日_期末值_月_期末值': ['当月后值', 'B', 60],
    # 日变季
    '日_当期值_季_当期同比': ['当季总值_当季同比', 'B_A', 500],
    '日_当期值_季_同比环差': ['当季总值_当季同比_当季环差', 'B_A_A', 600],
    '日_当期值_季_当期环比': ['当季总值_当季环比', 'B_A', 300],
    '日_当期值_季_累计值': ['当季总值_累计值', 'B_A', 300],
    '日_当期值_季_累计同比': ['当季总值_累计值_当季同比', 'B_A_A', 500],
    '日_当期值_季_当期值': ['当季总值', 'B', 300],
    # 日变季 期末值
    '日_期末值_季_期末同比': ['当季后值_当季同比', 'B_A', 500],
    '日_期末值_季_同比环差': ['当季后值_当季同比_当季环差', 'B_A_A', 500],
    '日_期末值_季_当期环比': ['当季后值_当季环比', 'B_A', 300],
    '日_期末值_季_累计值': ['-'],
    '日_期末值_季_累计同比': ['-'],
    '日_期末值_季_期末值': ['当季后值', 'B', 300],
    # 日变年
    '日_当期值_年_当期同比': ['当年均值_当年同比', 'B_A', 500],
    '日_当期值_年_同比环差': ['当年均值_当年同比_当年环差', 'B_A_A', 800],
    '日_当期值_年_当期环比': ['-'],
    '日_当期值_年_累计值': ['-'],
    '日_当期值_年_累计同比': ['-'],
    '日_当期值_年_当期值': ['当年总值', 'B', 500],
    # 日变年 期末值
    '日_期末值_年_期末同比': ['当年后值_当年同比', 'B_A', 500],
    '日_期末值_年_同比环差': ['当年后值_当年同比_当年环差', 'B_A', 800],
    '日_期末值_年_当期环比': ['-'],
    '日_期末值_年_累计值': ['-'],
    '日_期末值_年_累计同比': ['-'],
    '日_期末值_年_期末值': ['当年后值', 'B', 500],
    # 周变周
    '周_当期值_周_当期同比': ['-'],
    '周_当期值_周_同比环差': ['-'],
    '周_当期值_周_当期环比': ['当周环比', 'A', 6],
    '周_当期值_周_累计值': ['-'],
    '周_当期值_周_累计同比': ['-'],
    '周_当期值_周_当期值': ['-'],
    # 周变月
    '周_当期值_月_当期同比': ['当月均值_当月同比', 'B_A', 120],
    '周_当期值_月_同比环差': ['当月均值_当月同比', 'B_A_A', 120],
    '周_当期值_月_当期环比': ['当月均值_当月环比', 'B_A', 16],
    '周_当期值_月_累计值': ['当月总值_累计值', 'B_A', 120],
    '周_当期值_月_累计同比': ['当月总值_累计值_当月同比', 'B_A_A', 120],
    '周_当期值_月_当期值': ['当月总值', 'B', 8],
    # 周变季
    '周_当期值_季_当期同比': ['当季总值_当季同比', 'B_A', 120],
    '周_当期值_季_同比环差': ['当季总值_当季同比_环差', 'B_A', 120],
    '周_当期值_季_当期环比': ['当季总值_当季环比', 'B_A', 60],
    '周_当期值_季_累计值': ['当季总值_累计值', 'B_A', 120],
    '周_当期值_季_累计同比': ['当季总值_累计值_当季同比', 'B_A_A', 120],
    '周_当期值_季_当期值': ['当季总值', 'B', 60],
    # 周变年
    '周_当期值_年_当期同比': ['当年均值_当年同比', 'B_A', 120],
    '周_当期值_年_同比环差': ['当年均值_当年同比_环差', 'B_A', 120],
    '周_当期值_年_当期环比': ['-'],
    '周_当期值_年_累计值': ['-'],
    '周_当期值_年_累计同比': ['-'],
    '周_当期值_年_当期值': ['当年总值', 'B', 120],
    # 旬变旬
    '旬_当期值_旬_当期同比': ['当旬同比', 'A', 54],
    '旬_当期值_旬_同比环差': ['当旬同比_当旬环差', 'A_A', 54],
    '旬_当期值_旬_当期环比': ['当旬环比', 'A', 4],
    '旬_当期值_旬_累计值': ['-'],
    '旬_当期值_旬_累计同比': ['-'],
    '旬_当期值_旬_当期值': ['-'],
    # 旬变月
    '旬_当期值_月_当期同比': ['当月均值_当月同比', 'B_A', 54],
    '旬_当期值_月_同比环差': ['当月均值_当月同比_当月环差', 'B_A_A', 66],
    '旬_当期值_月_当期环比': ['当月总值_当月环比', 'B_A', 12],
    '旬_当期值_月_累计值': ['当月总值_累计值', 'B_A', 54],
    '旬_当期值_月_累计同比': ['当月总值_累计值_当月同比', 'B_A_A', 54],
    '旬_当期值_月_当期值': ['当月总值', 'B', 12],
    # 旬变季
    '旬_当期值_季_当期同比': ['当季总值_当季同比', 'B_A', 54],
    '旬_当期值_季_同比环差': ['当季总值_当季同比_当季环差', 'B_A_A', 66],
    '旬_当期值_季_当期环比': ['当季总值_当季环比', 'B_A', 36],
    '旬_当期值_季_累计值': ['当季总值_累计值', 'B_A', 54],
    '旬_当期值_季_累计同比': ['当季总值_累计值_当季同比', 'B_A_A', 54],
    '旬_当期值_季_当期值': ['当季总值', 'B', 36],
    # 旬变年
    '旬_当期值_年_当期同比': ['当年均值_当年同比', 'B_A', 72],
    '旬_当期值_年_当期同比': ['当年均值_当年同比_当年环差', 'B_A_A', 72],
    '旬_当期值_年_当期环比': ['-'],
    '旬_当期值_年_累计值': ['-'],
    '旬_当期值_年_累计同比': ['-'],
    '旬_当期值_年_当期值': ['当年总值', 'B', 54],
    # 月变月
    '月_当期值_月_当期同比': ['当月同比', 'A', 18],
    '月_当期值_月_同比环差': ['当月同比', 'A_A', 18],
    '月_当期值_月_当期环比': ['当月环比', 'A', 3],
    '月_当期值_月_累计值': ['累计值', 'A', 18],
    '月_当期值_月_累计同比': ['累计值_当月同比', 'A_A', 18],
    '月_当期值_月_当期值': ['-'],
    # 月变季
    '月_当期值_季_当期同比': ['当季均值_当季同比', 'B_A', 18],
    '月_当期值_季_同比环差': ['当季均值_当季同比_当季环差', 'B_A_A', 18],
    '月_当期值_季_当期环比': ['当季均值_当季环比', 'B_A', 12],
    '月_当期值_季_累计值': ['当季均值_累计值', 'B_A', 18],
    '月_当期值_季_累计同比': ['当季均值_累计值_当季同比', 'B_A_A', 18],
    '月_当期值_季_当期值': ['当季总值', 'B', 6],
    # 月变季 期末值
    '月_期末值_季_期末同比': ['当季后值_当季同比', 'B_A', 18],
    '月_期末值_季_同比环差': ['当季后值_当季同比_当季环差', 'B_A_A', 20],
    '月_期末值_季_当期环比': ['当季后值_当季环比', 'B_A', 12],
    '月_期末值_季_累计值': ['-'],
    '月_期末值_季_累计同比': ['-'],
    '月_期末值_季_期末值': ['当季后值', 'B', 6],
    # 月变年
    '月_当期值_年_当期同比': ['当年均值_当年同比', 'B_A', 18],
    '月_当期值_年_同比环差': ['当年均值_当年同比_当年环差', 'B_A_A', 30],
    '月_当期值_年_当期环比': ['-'],
    '月_当期值_年_累计值': ['-'],
    '月_当期值_年_累计同比': ['-'],
    '月_当期值_年_当期值': ['当年总值', 'B', 18],
    # 月变年 期末值
    '月_期末值_年_期末同比': ['当年后值_当年同比', 'B_A', 18],
    '月_期末值_年_同比环差': ['当年后值_当年同比_当年环差', 'B_A_A', 28],
    '月_期末值_年_当期环比': ['-'],
    '月_期末值_年_累计值': ['-'],
    '月_期末值_年_累计同比': ['-'],
    '月_期末值_年_当期值': ['当年后值', 'B', 18],
    # 季变季
    '季_当期值_年_当期同比': ['当年均值_当年同比', 'B_A', 6],
    '季_当期值_年_同比环差': ['当年均值_当年同比_当年环差', 'B_A_A', 9],
    '季_当期值_年_当期环比': ['-'],
    '季_当期值_年_累计值': ['累计值', 'A', 6],
    '季_当期值_年_累计同比': ['-'],
    '季_当期值_年_当期值': ['当年总值', 'B', 18],
    # 季变年
    '季_当期值_年_当期同比': ['当年均值_当年同比', 'B_A', 18],
    '季_当期值_年_同比环差': ['当年均值_当年同比_当年环差', 'B_A_A', 18],
    '季_当期值_年_当期环比': ['-'],
    '季_当期值_年_累计值': ['-'],
    '季_当期值_年_累计同比': ['-'],
    '季_当期值_年_当期值': ['当年总值', 'B', 18],
    # 季变年 期末值
    '季_期末值_年_期末同比': ['当年后值_当年同比', 'B_A', 18],
    '季_期末值_年_同比环差': ['当年后值_当年同比_当年环差', 'B_A_A', 18],
    '季_期末值_年_当期环比': ['-'],
    '季_期末值_年_累计值': ['-'],
    '季_期末值_年_累计同比': ['-'],
    '季_期末值_年_期末值': ['当年后值', 'B', 18],
    # 年变年 当期值
    '年_当期值_年_当期同比': ['当年均值_当年同比', 'B_A', 3],
    # 年变年 期末值
    '年_当期值_年_当期同比': ['当年均值_当年同比', 'B_A', 3],
    # 期末值比年初增减专题
    '日_期末值_日_比年初增减': ['比年初增减', 'A', 400],
    '旬_期末值_旬_比年初增减': ['比年初增减', 'A', 50],
    '月_期末值_月_比年初增减': ['比年初增减', 'A', 18],
    '季_期末值_季_比年初增减': ['比年初增减', 'A', 6],
    '日_期末值_日_比年初增减率': ['比年初增减率', 'A', 400],
    '旬_期末值_旬_比年初增减率': ['比年初增减率', 'A', 50],
    '月_期末值_月_比年初增减率': ['比年初增减率', 'A', 18],
    '季_期末值_季_比年初增减率': ['比年初增减率', 'A', 6],

    '月_累计值_月_累计值': ['-'],
    # 处理额外的时间序列
    '季_累计值_季_当期值': ['当季环差', 'A', 8],
    '季_累计值_季_当期同比': ['当季环差_当季同比', 'A', 8],
    '季_累计值_季_当期环比': ['当季环差_当季环比', 'A', 6],
    '季_累计值_季_累计同比': ['当季同比', 'A', 6],
    '月_累计值_季_当期值': ['当季后值', 'A', 13],
    '月_累计值_季_累计同比': ['当季后值_当季同比', 'A', 24],
    '月_累计值_季_当期同比': ['当月环差_当季均值_当季同比', 'A', 24],
    '月_累计值_季_当期环比': ['当月环差_当季均值_当季环比', 'A', 9],
    '月_累计值_月_当期值': ['当月环差', 'A', 12],
    '月_累计值_季_累计值': ['当季后值', 'B', 5],
    '月_累计值_月_当期同比': ['当月环差_当月同比', 'B', 18],
    '月_累计值_月_当期环比': ['当月环差_当月环比', 'B', 4],
    '月_累计值_月_累计同比': ['当月同比', 'A', 7]
    # '月_累计值_季_当期同比': ['月累计转季当期_当期同比', 'A_A', 6],
    #
}


class DateTransformer:
    """
    实例化日期类,用于生成所需要定位的日期,默认是今日
    td 今日
    根据今日日期，求：
    本月（季、年）初（末）
    上月（季、年）初（末）
    下月（季、年）初（末）
    上年本月（季）初（末）
    日期
    """

    def __init__(self, td: pd.Timestamp = None):
        super(DateTransformer, self).__init__()

        if not td:
            td = datetime.date.today()

        self.today = pd.to_datetime(td)
        self.year = self.today.year
        self.month = self.today.month
        self.day = self.today.day
        self.xun = self.detect_xun()

        self.xun_first_day_func_map = {
            '上旬': self.shang_xun_first_day, '中旬': self.zhong_xun_first_day, '下旬': self.xia_xun_first_day
        }
        self.xun_last_day_func_map = {
            '上旬': self.shang_xun_last_day, '中旬': self.zhong_xun_last_day, '下旬': self.xia_xun_last_day
        }

        self.cn_key_en_key_map = {
            '今日': 'td',
            '上日': ' ld',
            '上年本日': 'lytd',
            '本旬初': 'xfd',
            '本旬末': 'xld',
            '上旬初': 'lxfd',
            '上旬末': 'lxld',
            '下旬初': 'nxfd',
            '下旬末': 'nxld',
            '上年本旬初': 'lyxfd',
            '上年本旬末': 'lyxld',
            '本月初': 'mfd',
            '本月末': 'mld',
            '上月初': 'lmfd',
            '上月末': 'lmld',
            '下月初': 'nmfd',
            '下月末': 'nmld',
            '上年本月初': 'lymfd',
            '上年本月末': 'lymld',
            '本季初': 'qfd',
            '本季末': 'qld',
            '上季初': 'lqfd',
            '上季末': 'lqld',
            '下季初': 'nqfd',
            '下季末': 'nqld',
            '上年本季初': 'lyqfd',
            '上年本季末': 'lyqld',
            '本年初': 'yfd',
            '本年末': 'yld',
            '上年初': 'lyfd',
            '上年末': 'lyld',
            '下年初': 'nyfd',
            '下年末': 'nyld',
        }

    def check_date_freq(self, cn_freq):
        if cn_freq == '月':
            return self.today.is_month_end
        if cn_freq == '季':
            return self.today.is_quarter_end
        if cn_freq == '年':
            return self.today.is_year_end
        if cn_freq == '旬':
            for day in [10, 20]:
                if self.today.day == day:
                    return True
            return self.today.is_month_end
        return False

    def detect_xun(self):
        if self.day >= 21:
            return '下旬'
        if self.day >= 11:
            return '中旬'
        return '上旬'

    @property
    def last_day(self):
        return self.today + DateOffset(days=-1)

    @property
    def last_year_this_day(self):
        if not self.today.is_leap_year:
            return pd.to_datetime(datetime.datetime(self.year - 1, self.month, self.day))
        else:
            return pd.to_datetime(datetime.datetime(self.year - 1, self.month, self.day - 1))

    "---------------------------------旬度索引---------------------------------"

    def shang_xun_first_day(self):
        return self.month_first_day

    def zhong_xun_first_day(self):
        return pd.to_datetime(datetime.datetime(self.year, self.month, 11))

    def xia_xun_first_day(self):
        return pd.to_datetime(datetime.datetime(self.year, self.month, 21))

    def shang_xun_last_day(self):
        return pd.to_datetime(datetime.datetime(self.year, self.month, 10))

    def zhong_xun_last_day(self):
        return pd.to_datetime(datetime.datetime(self.year, self.month, 20))

    def xia_xun_last_day(self):
        return self.month_last_day

    @property
    def xun_first_day(self):
        return self.xun_first_day_func_map[self.xun]()

    @property
    def xun_last_day(self):
        return self.xun_last_day_func_map[self.xun]()

    @property
    def last_year_xun_first_day(self):
        if self.xun == '下旬':
            return pd.to_datetime(datetime.datetime(self.year - 1, self.month, 21))
        if self.xun == '中旬':
            return pd.to_datetime(datetime.datetime(self.year - 1, self.month, 11))
        return self.last_year_month_first_day

    @property
    def last_year_xun_last_day(self):
        return DateTransformer(self.last_year_xun_first_day).xun_last_day

    @property
    def last_xun_last_day(self):
        return self.xun_first_day + DateOffset(days=-1)

    @property
    def last_xun_first_day(self):
        return DateTransformer(self.last_xun_last_day).xun_first_day

    @property
    def next_xun_first_day(self):
        return self.xun_last_day + DateOffset(days=1)

    @property
    def next_xun_last_day(self):
        return DateTransformer(self.next_xun_first_day).xun_last_day

    "---------------------------------月度索引---------------------------------"

    @property
    def month_first_day(self):
        """本月第一天"""
        return self.today + MB(-1)

    @property
    def month_last_day(self):
        """本月最后一天"""
        return self.today + ME(0)

    @property
    def last_month_first_day(self):
        """上个月的第一天"""
        return self.today + MB(-2)

    @property
    def last_month_last_day(self):
        """上个月的最后一天"""
        return self.today + ME(-1)

    @property
    def next_month_first_day(self):
        """下个月的第一天"""
        return self.today + MB(0)

    @property
    def next_month_last_day(self):
        """下个月的最后一天"""
        return self.today + ME(2)

    @property
    def last_year_month_first_day(self):
        """上年本月第一天"""
        return self.today + MB(-13)

    @property
    def last_year_month_last_day(self):
        """上年本月最后一天"""
        return self.today + ME(-12)

    "---------------------------------季度索引----------------------------------"

    @property
    def quarter_first_day(self):
        """本季度第一天"""
        return self.today + QE(-1) + DateOffset(days=1)

    @property
    def quarter_last_day(self):
        """本季度最后一天"""
        return self.today + QE(0)

    @property
    def last_quarter_first_day(self):
        """上个季度第一天"""
        return self.today + QE(-2) + DateOffset(days=1)

    @property
    def last_quarter_last_day(self):
        """上个季度最后一天"""
        return self.today + QE(-1)

    @property
    def next_quarter_first_day(self):
        """下个季度第一天"""
        return self.today + QE(0) + DateOffset(days=1)

    @property
    def next_quarter_last_day(self):
        """下个季度最后一天"""
        return self.today + QE(2)

    @property
    def last_year_quarter_first_day(self):
        """上年本季度第一天"""
        return self.today + QE(-5) + DateOffset(days=1)

    @property
    def last_year_quarter_last_day(self):
        """上年本季度最后一天"""
        return self.today + QE(-4)

    "-------------------------------年度索引------------------------------------"

    @property
    def year_first_day(self):
        """本年第一天"""
        return self.today + YB(-1)

    @property
    def year_last_day(self):
        """本年最后一天"""
        return self.today + YE(0)

    @property
    def last_year_first_day(self):
        """上一年第一天"""
        return self.today + YB(-2)

    @property
    def last_year_last_day(self):
        """上年最后一天"""
        return self.today + YE(-1)

    @property
    def next_year_first_day(self):
        """下一年第一天"""
        return self.today + YB(0)

    @property
    def next_year_last_day(self):
        """下一年最后一天"""
        return self.today + YE(2)

    def to_ten_day_end(self):
        if self.today.day in [1, 2, 3, 4, 5, 6, 7, 8, 9]:
            month = self.today.month
            year = self.today.year
            return pd.to_datetime(datetime.date(year, month, 10))
        elif self.today.day in [11, 12, 13, 14, 15, 16, 17, 18, 19]:
            month = self.today.month
            year = self.today.year
            return pd.to_datetime(datetime.date(year, month, 20))
        else:
            return self.month_last_day

    @property
    def all_cn_time_stamp(self):
        return {
            '今日': self.today,
            '上日': self.last_day,
            '上年本日': self.last_year_this_day,
            '本旬初': self.xun_first_day,
            '本旬末': self.xun_last_day,
            '上旬初': self.last_xun_first_day,
            '上旬末': self.last_xun_last_day,
            '下旬初': self.next_xun_first_day,
            '下旬末': self.next_xun_last_day,
            '上年本旬初': self.last_year_xun_first_day,
            '上年本旬末': self.last_year_xun_last_day,
            '本月初': self.month_first_day,
            '本月末': self.month_last_day,
            '上月初': self.last_month_first_day,
            '上月末': self.last_month_last_day,
            '下月初': self.next_month_first_day,
            '下月末': self.next_month_last_day,
            '上年本月初': self.last_year_month_first_day,
            '上年本月末': self.last_year_month_last_day,
            '本季初': self.quarter_first_day,
            '本季末': self.quarter_last_day,
            '上季初': self.last_quarter_first_day,
            '上季末': self.last_quarter_last_day,
            '下季初': self.next_quarter_first_day,
            '下季末': self.next_quarter_last_day,
            '上年本季初': self.last_year_quarter_first_day,
            '上年本季末': self.last_year_quarter_last_day,
            '本年初': self.year_first_day,
            '本年末': self.year_last_day,
            '上年初': self.last_year_first_day,
            '上年末': self.last_year_last_day,
            '下年初': self.next_year_first_day,
            '下年末': self.next_year_last_day,
        }

    @property
    def all_en_time_stamp(self):
        return {self.cn_key_en_key_map[k_]: v_ for k_, v_ in self.all_cn_time_stamp.items()}

    @property
    def all_str_time_cn_timestamp(self):
        return {k_: v_.strftime("%Y-%m-%d") for k_, v_ in self.all_cn_time_stamp.items()}


class DataTransformer:
    def __init__(self, se, cn_freq, log=[]):
        super(DataTransformer, self).__init__()

        self.se = se
        self.se.index = pd.to_datetime(se.index)
        self.dict_data = self.se.to_dict()
        self.cn_freq = cn_freq
        self.log = log
        self.item = ''

        self.chinese_freq_li = ['日', '周', '月', '季', '年']
        self.english_freq_li = ['D', 'W', 'M', 'Q', 'Y']
        self.freq_cn_to_en = dict(zip(self.chinese_freq_li, self.english_freq_li))
        self.yoy_mom_li = ['当日同比', '当日环比', '当旬同比', '当旬环比', '当月同比', '当月环比', '当季同比',
                           '当季环比', '当年同比',
                           '当日环差', '当旬环差', '当月环差', '当季环差', '当年环差']
        self.mean_first_last_sum_li = [
            '当月均值', '当月前值', '当月后值', '当月总值', '当周均值', '当周前值', '当周后值', '当周总值',
            '当季均值', '当季前值', '当季后值', '当季总值', '当年均值', '当年前值', '当年后值', '当年总值',
        ]
        self.year_begin_li = ['比年初增长', '比年初增长率']
        self.xun_li = ['当旬均值', '当旬前值', '当旬后值', '当旬总值']

        if len(se.dropna()) == 0:
            self.is_empty = True
        else:
            self.se.sort_index(inplace=True)
            self.is_empty = False
            self.freq_yoy_map = {'旬': '上年本旬末', '月': '上年本月末', '季': '上年本季末', '年': '上年末'}
            self.freq_mom_map = {'旬': '上旬末', '月': '上月末', '季': '上季末', '年': '上年末'}

    def every_ten_days_data(self):
        all_idx_date = []
        for idx in self.se.index:
            if idx.day in [10, 20]:
                all_idx_date.append(idx)
            elif idx.is_month_end:
                all_idx_date.append(idx)
            elif idx == self.se.index[-1]:
                idx_tran = DateTransformer(idx).to_ten_day_end()
                all_idx_date.append(idx_tran)
        dic = {}
        for i in range(len(all_idx_date)):
            t_start = all_idx_date[i - 1]
            t_end = all_idx_date[i]
            dic[t_end] = self.se[t_start:t_end]
        return dic

    def __getitem__(self, item):
        """
        :param item:当(周，月，季，年）均值，当（月，季，年）同比，滞后【i】期
        :return:
        """
        self.item = item
        if self.is_empty:
            return DataTransformer(pd.Series(), cn_freq=item[1], log=self.log)
        if item in self.yoy_mom_li:
            return DataTransformer(self.pct_change(item), cn_freq=item[1], log=self.log)
        if item in self.mean_first_last_sum_li:
            data_transformer = self.get_w_m_q_y_func(item)().dropna()
            return DataTransformer(data_transformer, cn_freq=item[1], log=self.log)
        if item == '累计值':
            li = self.cum_sum()
            if len(li) > 0:
                return DataTransformer(pd.concat(li, axis=0), cn_freq=self.cn_freq, log=self.log)
            else:
                self.log.append(f"最终没有符合条件的累计值计算结果")
                return DataTransformer(pd.Series(), cn_freq=self.cn_freq, log=self.log)
        if item in self.xun_li:
            xun_data_dic = self.xun_data_process(item)
            if len(xun_data_dic) > 0:
                return DataTransformer(pd.Series(xun_data_dic), cn_freq=self.cn_freq, log=self.log)
            else:
                self.log.append(f"最终没有符合条件的{item}计算结果")
                return DataTransformer(pd.Series(), cn_freq=self.cn_freq, log=self.log)

    def xun_data_process(self, item):
        xun_data_dic = {}
        for t, sample in self.every_ten_days_data().items():
            sample = sample.dropna()
            if len(sample) == 0:
                value = np.nan
            else:
                if item == '当旬均值':
                    value = sample.mean()
                elif item == '当旬前值':
                    value = sample[0]
                elif item == '当旬总值':
                    value = sample.sum()
                else:
                    value = sample[-1]
            xun_data_dic[t] = value
        return xun_data_dic

    def cum_sum(self):
        data_sum = pd.DataFrame(self.se)
        data_sum['year'] = data_sum.index.year
        li = []
        for year, df in data_sum.groupby('year'):
            se = df.iloc[:, 0].cumsum()
            idx_se = self.check_sum_data(se)
            if len(idx_se) > 0:
                li.append(se[idx_se])
            else:
                self.log.append(f"本年当月值中最小日期索引为{min(se.index)}，无法计算累计值")
        return li

    def check_sum_data(self, se):
        if self.cn_freq == '月':
            months = [s.month for s in se.index]  # 获取序列中出现的所有月份
            miss_months = [s for s in range(1, 13) if s not in months]  # 获取序列中缺失的月份
            se_index = se.index
            # 对任一缺失的月份，只要indx里出现比其大的月份，就应该删除（比如缺了一月，那么所有的累计值就没有意义）
            for miss_month in miss_months:
                se_index = [m for m in se_index if m.month <= miss_month]
        elif self.cn_freq == '季':
            quarters = [s.quarter for s in se.index]
            miss_quarters = [s for s in range(1, 13) if s not in quarters]
            se_index = se.index
            for miss_quarter in miss_quarters:
                se_index = [m for m in se_index if m.quarter <= miss_quarter]
        # elif self.cn_freq == '旬':

        return se_index

    def get_w_m_q_y_func(self, text):  # 前值、均值、后值的选择
        resample = self.se.resample(self.freq_cn_to_en[text[1]])
        func_map = {'均': resample.mean, '前': resample.first, '后': resample.last, '总': resample.sum}
        return func_map[text[2]]

    def check_input_freq(self, cn_freq):
        if self.cn_freq != cn_freq:
            self.log.append(f"原始数据不是{cn_freq}频，拒绝计算")
            return False
        else:
            self.log.append(f"{cn_freq}频率检验正常")
            return True

    def pct_change(self, item):
        cn_freq = item[-3]

        if not self.check_input_freq(cn_freq):
            return pd.Series()

        se_out = {}
        for t, value in self.dict_data.items():
            good, v_cal = self.basic_cal_data(t, value, cn_freq, item)
            if good:
                se_out[t] = v_cal
        return pd.Series(se_out, dtype=float)

    def basic_cal_data(self, t, value, cn_freq, item):
        t_str = t.strftime("%Y-%m-%d")

        if value == 0:
            self.log.append(f"计算{item}索引分子（减数）日期：{t_str}数据异常为0")
            return False, 0

        if not DateTransformer(t).check_date_freq(cn_freq):
            self.log.append(f"{t_str}不是{cn_freq}末值，无法计算")
            return False, 0

        if item[-2:] == '同比':
            t_dividend = DateTransformer(t).all_cn_time_stamp[self.freq_yoy_map[cn_freq]]
        else:
            t_dividend = DateTransformer(t).all_cn_time_stamp[self.freq_mom_map[cn_freq]]

        t_dividend_str = t_dividend.strftime("%Y-%m-%d")

        if t_dividend not in self.dict_data:
            self.log.append(f"计算{item}索引分母（被减数）日期：{t_dividend_str}无数据")
            return False, 0

        v_dividend = self.dict_data[t_dividend]

        if np.isnan(v_dividend):
            self.log.append(f"计算{item}索引分母（被减数）日期：{t_dividend_str}数据异常为nan")
            return False, 0

        if v_dividend == 0:
            self.log.append(f"计算{item}索引分母（被减数）日期：{t_dividend_str}数据异常为0")
            return False, 0

        if item[-2:] == '环差':
            return True, value - v_dividend
        else:
            return True, 100 * (value / v_dividend) - 100


def concat_string(unique_string_data):
    """
    把列表中字符串拼接起来，如果为'-'则不处理
    :param unique_string_data:
    :return:
    """
    r_s = ''
    for s in unique_string_data:
        if s != '-':
            r_s = f"{r_s}-{s}"
    return r_s[1:]


def save_pickle(data, save_name):
    with open(save_name, 'wb') as f:
        pickle.dump(data, f)
    return save_name


def reformat_date(freq_raw, date):
    """
    把不同类型的时间序列书格式化为统一的格式
    :param freq_raw: 原始频率，有['T', 'M', 'Q', 'Y']
    :param date:
    :return:
    """
    if freq_raw == 'T':
        year_month = date[:6]
        year = int(year_month[:4])
        month = int(year_month[4:])
        if date[-2] == '上':
            ans = datetime.date(year, month, 10)
        elif date[-2] == '中':
            ans = datetime.date(year, month, 20)
        else:
            ans = datetime.date(year, month, 21) + MonthEnd()
    elif freq_raw == 'M':
        year = int(date[:4])
        month = int(date[4:])
        date_ = datetime.datetime(year, month, 1)
        ans = date_ + MonthEnd()
    elif freq_raw == 'Q':
        year = int(date[:4])
        quarter = int(date[-1])
        if quarter not in [1, 2, 3, 4]:
            return datetime.date(2035, 12, 31)
        month = quarter * 3
        date_ = datetime.datetime(year, month, 1)
        print(date, date_)
        ans = date_ + MonthEnd()
    elif freq_raw == 'Y':
        return datetime.date(int(date), 12, 31)
    else:
        ans = pd.to_datetime(date)
    return ans.strftime('%Y-%m-%d')


if __name__ == "__main__":
    import pickle

    # date_tran = DateTransformer('2020-02-29')
    # for k, v in date_tran.all_cn_time_stamp.items():
    #     print(k, v)
    # for k, v in date_tran.all_en_time_stamp.items():
    #     print(k, v)

    paths = os.listdir()
    paths = [s for s in paths if 'upload_df' in s]
    li = []
    for path in paths:
        data = pd.read_pickle(path)
        for target_freq, freq_df in data.groupby('target_freq'):
            print(target_freq, freq_df.shape)
